﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "UiPlatformUtils.h"
#include "IApplication.h"
#include "IMainWindow.h"
#include "IUiDocumentViewManager.h"
#include "IUiDocument.h"
#include "UiInterfaceEnums.h"
#include "IRibbon.h"
#include "IRibbonPage.h"
#include "IRibbonContextualPage.h"
#include "IRibbonGroup.h"
#include "IStatusBarPanel.h"
#include "IStatusBar.h"
#include "IPropertyWidget.h"
#include "IDockManager.h"
#include "IGalleryDefinition.h"
#include "ILabelDefinition.h"
#include "CommandIds.h"
#include "UiDocumentViewUtils.h"
#include "IModelView.h"
#include "IUiManager.h"
#include "IControl.h"
#include "GcmpActionBase.h"
#include "IRibbonContextualPage.h"

#include "IDocument.h"
#include "IUiView.h"
#include "Vector3dUtils.h"
#include "IDrawingLayoutManager.h"
#include "IUserTransaction.h"
#include "IDrawingViewport.h"
#include "IDrawingLayout.h"
#include "ICategoryLibrary.h"
#include "ICategory.h"

#include "ICommandButtonDefinition.h"
#include "ICommandButtonMenuDefinition.h"
#include "ICommandMenuItemDefinition.h"

#include "PropertyWidgetUtils.h"
#include "UiCommonDialog.h"
#include "ICanvas.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

const wchar_t* TR_MODULE_NAME = L"UIPlatForm";

using namespace gcmp;
using namespace Sample;

gcmp::IMainWindow* UiPlatformUtils::GetMainWindow()
{
    IApplication *pApplication = IApplication::Get();
    if (!pApplication)
    {
        return nullptr;
    }
    return IMainWindow::GetMainWindow();
}

gcmp::IUiDocumentViewManager* UiPlatformUtils::GetUiDocumentViewManager()
{
    IMainWindow *pMainWindow = GetMainWindow();
    if (!pMainWindow)
    {
        return nullptr;
    }
    return IUiDocumentViewManager::Get();
}


gcmp::IDockManager* UiPlatformUtils::GetDockManager()
{
    IMainWindow *pMainWindow = GetMainWindow();
    if (!pMainWindow)
    {
        return nullptr;
    }
    return IUiManager::Get()->GetDockManager();
}

//gcmp::IDock* MiniProject::UiPlatformUtils::GetOrCreateElementTreeWidgetDock()
//{
//    const std::wstring elementTreeViewName = IElementTreeWidget::GetName();
//    IDockManager *pDockManager = GetDockManager();
//    if (!pDockManager)
//    {
//        return nullptr;
//    }
//    if (!pDockManager->GetDock(elementTreeViewName))
//    {
//        OwnerPtr<IDock> opPropertyPanel = pDockManager->CreateDock(elementTreeViewName, GBMP_TR(L"结构视图"));
//        opPropertyPanel->SetWidget(TransferOwnership(IElementTreeWidget::Create()));
//        pDockManager->AddDock(TransferOwnership(opPropertyPanel), DockArea::Left,
//            DockOrientation::Horizontal);
//    }
//    return pDockManager->GetDock(elementTreeViewName);
//}

bool UiPlatformUtils::IsInDrawingEnvironment()
{
    if (UiDocumentViewUtils::GetCurrentDocument() == nullptr)
    {
        return false;
    }
    IModelView *pModelView = UiDocumentViewUtils::GetCurrentModelView();
    if (!pModelView)
    {
        return false;
    }
    return pModelView->GetViewType() == BuiltInViewType::Drawing;
}

bool UiPlatformUtils::IsInProjectEnvironment()
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    if (pDoc == nullptr)
    {
        return false;
    }
    return pDoc->IsFamilyDocument() ? false : true;
}

void UiPlatformUtils::SetStatusBarPromptMessage(const std::wstring &message)
{
    IMainWindow* pMainWindow = IMainWindow::GetMainWindow();
    IStatusBar* pStatusBar = pMainWindow->GetStatusBar();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pStatusBar, L"pStatusBar为空", L"GDMP", L"2023-09-30");
    IStatusBarPanel* pPanel = pStatusBar->GetPanel(ID_STATUS_BAR_PANEL_PROMPT);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPanel, L"pPanel为空", L"GDMP", L"2023-09-30");
    IControl* pLabelCtrl = pPanel->GetControl(ID_STATUS_BAR_LABEL_PROMPT);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pLabelCtrl, L"pLabelCtrl为空", L"GDMP", L"2023-09-30");
    ILabelDefinition* pLabelDef = dynamic_cast<ILabelDefinition*>(pLabelCtrl->GetControlDefinition());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pLabelDef, L"pLabelDef为空", L"GDMP", L"2023-09-30");
    // TODO:GBMP-45577 底部状态栏不够显示Lab输出的各种信息，需要单独做个Qt控件显示输出信息
    pLabelDef->SetCaption(message);
}

void UiPlatformUtils::SetupActionContext(gcmp::IAction *pAction, const std::wstring &pageName,
    const std::wstring& contextualPageCaption,
    const std::vector<CommandContextDefinition> &definitions)
{
    OwnerPtr<IRibbonGroup> opGroup = IRibbonGroup::Create(L"demoRuntimeDynamicGroup", L"绘制");
    OwnerPtr<IGalleryDefinition> opGalleryDefine = IGalleryDefinition::Create(L"demoRuntimeDynamicGallery", L"几何方法");
    for (auto item : definitions)
    {
        opGalleryDefine->AddItem(item.CommandId, item.Name, item.Tooltip, item.IconPath, std::wstring());
    }
    opGalleryDefine->SetCurrentGalleryItem(definitions[0].CommandId);
    opGroup->AddGallery(TransferOwnership(opGalleryDefine));
    std::vector<gcmp::OwnerPtr<IRibbonGroup>> controlGroups;
    controlGroups.emplace_back(TransferOwnership(opGroup));
    GcmpActionBase *pActionBase = dynamic_cast<GcmpActionBase*>(pAction);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pActionBase, L"pActionBase为空", L"GDMP", L"2023-09-30");
    pActionBase->AddDynamicGroup(pageName, TransferOwnership(controlGroups), contextualPageCaption);
}


gcmp::IModelView* GetOrCreateModelViewDrawing(gcmp::IDocument* pDocument, const std::wstring viewName/*L"ModelViewForDrawing"*/)
{
    gcmp::IModelView* pViewDrawing = nullptr;
    if (nullptr == pDocument)
    {
        return pViewDrawing;
    }

    for each (gcmp::IModelView* pModelView in gcmp::IModelView::GetAllModelViews(pDocument))
    {
        if (gcmp::BuiltInViewType::Drawing != pModelView->GetViewType())
        {
            continue;
        }

        if (!(gcmp::Vector3dUtils::IsEqual(Vector3d(1, 0, 0), pModelView->GetRightDirection()) && gcmp::Vector3dUtils::IsEqual(Vector3d(0, 1, 0), pModelView->GetUpDirection())))
        {
            continue;
        }

        if (pModelView->GetName() == viewName)
        {
            pViewDrawing = pModelView;
            break;
        }
    }

    if (nullptr == pViewDrawing)
    {
        OwnerPtr<IUserTransaction> opUserTransaction = gcmp::IUserTransaction::Create(pDocument, L"创建图纸视图");

        gcmp::IDrawingLayoutManager* pDrawingLayoutMgr = gcmp::IDrawingLayoutManager::Get(pDocument);
        if (nullptr == pDrawingLayoutMgr)
        {
            opUserTransaction->Rollback();
            return nullptr;
        }
        std::wstring errorMsg = L"";
        gcmp::IDrawingLayout* pLayout = pDrawingLayoutMgr->CreateLayout(viewName, &errorMsg);
        if (nullptr == pLayout)
        {
            opUserTransaction->Rollback();
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"发生错误"), errorMsg, (int)UiCommonDialog::ButtonType::OK);
            return nullptr;
        }

        pViewDrawing = pLayout->GetModelView();
        gcmp::ICategoryLibrary* pCategoryLibrary = gcmp::ICategoryLibrary::Get(pDocument);
        if (nullptr != pCategoryLibrary)
        {
            for (const gcmp::ICategory* pCategory : pCategoryLibrary->GetAllCategories())
            {
                const std::wstring categoryName = pCategory->GetName();
                if (categoryName == L"模型线" || categoryName == L"定制直线" || categoryName == L"临时对象样式")
                {
                    pViewDrawing->SetElementsVisibilityByCategoryUid(pCategory->GetUniIdentity(), false);
                }
            }
        }
        pViewDrawing->SetViewScale(5.0);
        pViewDrawing->SetDetailLevel(ModelViewDetailLevel::Fine);
        opUserTransaction->Commit();
    }

    return pViewDrawing;
}

bool CheckDrawingLayoutAndViewPort(const gcmp::IModelView* pModelViewDrawing)
{
    if (nullptr == pModelViewDrawing)
    {
        return false;
    }
    if (pModelViewDrawing->GetViewType() != BuiltInViewType::Drawing && pModelViewDrawing->GetViewType() != BuiltInViewType::Perspective)
    {
        return false;
    }

    gcmp::IDrawingLayoutManager* pDrawingLayoutManager = gcmp::IDrawingLayoutManager::Get(pModelViewDrawing->GetDocument());
    if (pDrawingLayoutManager == nullptr)
    {
        return false;
    }

    gcmp::IDrawingLayout* pDrawingLayout = nullptr;
    std::vector<gcmp::IDrawingLayout*> pDrawingLayouts;
    for (gcmp::IDrawingLayout* pDrawingLayoutItem : pDrawingLayoutManager->GetAllLayouts())
    {
        pDrawingLayouts.emplace_back(pDrawingLayoutItem);
        if (pDrawingLayoutItem->GetModelView()->GetElementId().AsInt64() == pModelViewDrawing->GetElementId().AsInt64())
        {
            pDrawingLayout = pDrawingLayoutItem;
            break;
        }
    }

    if (nullptr == pDrawingLayout)
    {
        OwnerPtr<IUserTransaction> opUserTransaction = IUserTransaction::Create(pModelViewDrawing->GetDocument(), L"CreateDrawingLayout", true);

        pDrawingLayout = pDrawingLayoutManager->CreateLayout(L"DrawingLayout", nullptr);
        if (nullptr == pDrawingLayout)
        {
            opUserTransaction->Rollback();
            return false;
        }

        opUserTransaction->Commit();
    }

    gcmp::IDrawingViewport* pDrawingViewPort = nullptr;
    for (gcmp::IDrawingViewport* pDrawingViewPortItem : pDrawingLayout->GetAllViewports())
    {
        if (pModelViewDrawing->GetElementId() == pDrawingViewPortItem->GetModelViewId())
        {
            pDrawingViewPort = pDrawingViewPortItem;
            break;
        }
    }

    if (nullptr == pDrawingViewPort)
    {
        OwnerPtr<IUserTransaction> opUserTransaction = IUserTransaction::Create(pModelViewDrawing->GetDocument(), L"CreateViewPort", true);
        pDrawingViewPort = pDrawingLayout->CreateViewport(pModelViewDrawing->GetElementId(), L"DefaultViewPort", Vector3d(0, 0, 0), nullptr);
        if (pDrawingViewPort == nullptr)
        {
            opUserTransaction->Rollback();
            return false;
        }
        pDrawingViewPort->SetFrameVisibility(GraphicsNodeVisibility::Always);
        pDrawingViewPort->SetIsEnableActive(true);
        pDrawingViewPort->SetIsSwitchActiveState(true);
        //pDrawingViewPort->SetAnchorPoint(ViewportAnchorPointType::BottomLeft);

        opUserTransaction->Commit();
    }

    return true;
}


bool UiPlatformUtils::CreateUiViewDrawing(gcmp::IUiDocument* pUiDocument, const std::wstring viewName, gcmp::IUiView* &pUiViewDrawing)
{
    pUiViewDrawing = nullptr;
    if (nullptr == pUiDocument)
    {
        return false;
    }

    //1.检查打开的视图是否有图纸视图
    for each (IUiView* pUiView in pUiDocument->GetAllUiViews())
    {
        if (pUiView->IsSubUiView())
        {
            continue;
        }

        if (gcmp::BuiltInViewType::Drawing != pUiView->GetModelView()->GetViewType())
        {
            continue;
        }

        gcmp::IModelView* pModelViewDrawing = pUiView->GetModelView();
        if (!(gcmp::Vector3dUtils::IsEqual(Vector3d(1, 0, 0), pModelViewDrawing->GetRightDirection()) && gcmp::Vector3dUtils::IsEqual(Vector3d(0, 0, 1), pModelViewDrawing->GetUpDirection())))
        {
            //continue;
        }

        if (pUiView->GetTag() == viewName)
        {
            pUiViewDrawing = pUiView;
            break;
        }
    }

    //2.有的话直接打开
    if (pUiViewDrawing != nullptr)
    {
        if (gcmp::UiDocumentViewUtils::GetCurrentUiView()->GetId() != pUiViewDrawing->GetId())
        {
            gcmp::IModelView* pModelView = pUiViewDrawing->GetModelView();
            CheckDrawingLayoutAndViewPort(pUiViewDrawing->GetModelView());
            gcmp::IMainWindow::GetMainWindow()->CreateOrOpenUiView(pUiDocument->GetId(), pUiViewDrawing->GetModelView()->GetElementId(), false, pUiViewDrawing->GetTag());
        }
        else
        {
            pUiViewDrawing->GetCanvas()->Refresh();
        }

        return true;
    }

    //3.没有的话继续检查文档是否有图纸模型
    gcmp::IModelView* pModelViewDrawing = GetOrCreateModelViewDrawing(pUiDocument->GetDbDocument(), L"ModelViewForDrawing");
    if (nullptr == pModelViewDrawing)
    {
        return false;
    }

    pUiViewDrawing = gcmp::IMainWindow::GetMainWindow()->CreateOrOpenUiView(pUiDocument->GetId(), pModelViewDrawing->GetElementId(), false, viewName);
    return (nullptr != pUiViewDrawing);
}

void UiPlatformUtils::AddPage(const std::wstring& id, const std::wstring& caption)
{
    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWnd, L"获取主窗口失败", L"GDMP", L"2023-09-30");
    IRibbon* pRibbon = pMainWnd->GetRibbon();
    OwnerPtr<IRibbonPage> opPageAPI = IRibbonPage::Create(id, caption);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRibbon, L"获取RibbonBar失败", L"GDMP", L"2023-09-30");
    pRibbon->AddPage(TransferOwnership(opPageAPI));
}

gcmp::IRibbonGroup* UiPlatformUtils::FindGroup(const std::wstring& pageId, const std::wstring& groupId)
{
    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pMainWnd, L"获取主窗口失败", L"GDMP", L"2023-09-30");

    IRibbon* pRibbon = pMainWnd->GetRibbon();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRibbon, L"获取RibbonBar失败", L"GDMP", L"2023-09-30");
    //建模
    IRibbonPage* pPage = pRibbon->GetPage(pageId);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPage, L"获取建模标签页失败", L"GDMP", L"2023-09-30");

    return pPage->GetGroup(groupId);
}

gcmp::IRibbonGroup* UiPlatformUtils::GetGroup(const std::wstring& pageId, const std::wstring& groupId, const std::wstring& groupName)
{
    IMainWindow* pMainWnd = IMainWindow::GetMainWindow();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pMainWnd, L"获取主窗口失败", L"GDMP", L"2023-09-30");

    IRibbon* pRibbon = pMainWnd->GetRibbon();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRibbon, L"获取RibbonBar失败", L"GDMP", L"2023-09-30");
    //建模
    IRibbonPage* pPage = pRibbon->GetPage(pageId);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPage, L"获取建模标签页失败", L"GDMP", L"2023-09-30");

    IRibbonGroup* pGroup = pPage->GetGroup(groupId);
    if (pGroup)
    {
        return pGroup;
    }

    OwnerPtr<IRibbonGroup> opGroup = IRibbonGroup::Create(groupId, groupName);
    if (pPage->AddGroup(TransferOwnership(opGroup)))
    {
        return pPage->GetGroup(groupId);
    }
    return nullptr;
}

bool UiPlatformUtils::LoadButtons(gcmp::IRibbonGroup* pGroup, const std::vector<AddinButton>& btns)
{
    if (!pGroup)
    {
        return false;
    }
    for (auto&& obj : btns)
    {
        if (obj.subs.empty())
        {
            OwnerPtr<ICommandButtonDefinition> opItem =
                ICommandButtonDefinition::Create(obj.id, GBMP_TR(obj.title).c_str(), GBMP_TR(obj.title).c_str(), obj.id, obj.icon);
            pGroup->AddButton(TransferOwnership(opItem));
        }
        else
        {
            OwnerPtr<ICommandButtonMenuDefinition> opItem =
                ICommandButtonMenuDefinition::Create(obj.id, obj.subs[0].id, GBMP_TR(obj.title).c_str(), obj.icon);

            for (auto&& sub : obj.subs)
            {
                OwnerPtr<ICommandMenuItemDefinition> opSub =
                    ICommandMenuItemDefinition::Create(sub.id, sub.id, GBMP_TR(sub.title).c_str(), GBMP_TR(sub.title).c_str(), sub.icon);
                opItem->AddItem(TransferOwnership(opSub));
            }
            pGroup->AddButtonMenu(TransferOwnership(opItem));
        }
    }
    return true;
}

void ModuleUIUtils::SetupModuleUI(gcmp::OwnerPtr<gcmp::IRibbonGroup> opRibbonGroup, const std::wstring& contextualPageCaption)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(opRibbonGroup, L"opRibbonGroup为空", L"GDMP", L"2023-09-30");

    // 将来改为缓存
    RemoveModuleUI();

    IMainWindow* pMainWindow = UiPlatformUtils::GetMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMainWindow, L"pMainWindow为空", L"GDMP", L"2023-09-30");

    IRibbon* pRibbon = pMainWindow->GetRibbon();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRibbon, L"pRibbon为空", L"GDMP", L"2023-09-30");
        
    IRibbonPage* pRibbonPage = pRibbon->GetActivatedPage();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pRibbonPage, L"pRibbonPage为空", L"GDMP", L"2023-09-30");
    m_opRibbonContextualPage = IRibbonContextualPage::Create();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_opRibbonContextualPage, L"m_opRibbonContextualPage为空", L"GDMP", L"2023-09-30");

    m_opRibbonContextualPage->AddGroup(pRibbonPage->GetPageId(), TransferOwnership(opRibbonGroup), contextualPageCaption);
}

void ModuleUIUtils::RemoveModuleUI()
{
    if (m_opRibbonContextualPage)
    {
        m_opRibbonContextualPage->DeleteAllGroups();
        m_opRibbonContextualPage->ActivatePreviousPage();
        PropertyWidgetUtils::SetDefalutElementId(ElementId::InvalidID);
    }
}

ModuleUIUtils* ModuleUIUtils::Get()
{
    static ModuleUIUtils moduleUIUtils;
    return &moduleUIUtils;
}

